home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / Sound / 'vox ' recording / VoxII.c next >
Encoding:
C/C++ Source or Header  |  1995-02-11  |  9.1 KB  |  350 lines  |  [TEXT/MPS ]

  1. /*______________________________________________________*/
  2. /*                       Sound  Demo                        */
  3. /*                          by                          */
  4. /*                  RICHARD P. COLLYER                  */
  5. /*              Developer Technical Support             */
  6. /*                 Apple Computer, Inc.                 */
  7. /*                       09/24/91                       */
  8. /*______________________________________________________*/
  9.  
  10. #include    <GestaltEqu.h>
  11. #include    <Memory.h>
  12. #include    <OSEvents.h>
  13. #include    <Sound.h>
  14. #include    <SoundInput.h>
  15. #include    <StdIO.h>
  16. #include    <Types.h>
  17.  
  18. //The smaller buffSize, the sooner the echo, but the more clicks you hear
  19. #define kbuffSize        0x10000
  20.  
  21. /*The HeaderSize constant is used to skip 20 bytes of the buffer when calling bufferCmd.
  22. The first 20 byte of the sound header need to be skipped so that the bufferCmd will be
  23. pointing at a SoundHeader Record and not an 'snd ' resource header. */
  24. #define kHeaderSize        20
  25.  
  26. // Forward reference
  27. pascal void MyRecComp (SPBPtr inParamPtr);
  28.  
  29. typedef struct {
  30.     short        OnOff;
  31.     short         Level;
  32.     short         Length;
  33. } Level;
  34.  
  35.  
  36. void BufPlay (Handle Buf, SndChannelPtr    channel)
  37.  
  38. /*This routine takes an snd buffer and a sound channel and turns the information into a 
  39. bufferCmd to the channel. */
  40.  
  41. {
  42.     SndCommand        localSndCmd;
  43.     OSErr            err;
  44.     
  45.     localSndCmd.cmd = bufferCmd;
  46.     localSndCmd.param1 = 0;
  47.     localSndCmd.param2 = (long) ((*Buf) + kHeaderSize);
  48.     
  49.     err = SndDoCommand (channel, &localSndCmd, false);
  50.     if (err != noErr)
  51.         Debugger();
  52.     return;
  53. }
  54.  
  55. Handle SetUpSounds (Handle Buf, short *HeaderSize, Fixed sampRate)
  56.  
  57. /* SetUpSounds is a routine which takes a buffer handle, sound headers size and sample rate 
  58. value and turns it into a snd buffer with the proper header.  It then returns the buffer
  59. handle back to the caller. */
  60.  
  61. {
  62.     OSErr        err;
  63.     short        dummy;
  64.  
  65.     
  66.     Buf = NewHandle(kbuffSize);
  67.     if (MemError() != noErr || Buf == nil)
  68.         Debugger();
  69.     MoveHHi (Buf);
  70.     if (MemError() != noErr)
  71.         Debugger();
  72.     HLock (Buf);
  73.     if (MemError() != noErr)
  74.         Debugger();
  75.     
  76.     /* The call to SetupSndHeader is done twice in order to make sure that the 
  77.     Header size is set correctly.  */
  78.  
  79.     err = SetupSndHeader (Buf, 1, sampRate, 8, 'NONE', 0x3C, 0, HeaderSize);
  80.     if (err != noErr)
  81.         Debugger();
  82.     err = SetupSndHeader (Buf, 1, sampRate, 8, 'NONE', 0x3C, kbuffSize - *HeaderSize, &dummy);
  83.     if (err != noErr)
  84.         Debugger();
  85.         
  86.     return (Buf);
  87. }
  88.  
  89. main()
  90. {
  91.     short                dummy;
  92.     Level                myLevel;
  93.     OSErr                err;
  94.     SPBPtr                RecordRec;
  95.     long                SoundRefNum, feature;
  96.     Handle                Buffer, Buffer2, Buffer3, Buffer4;
  97.     SndChannelPtr        chan;
  98.     short                headerlength, headerlength2, headerlength3, headerlength4;
  99.     Fixed                sampleRate;
  100.     SndCommand            mycmd;
  101.     short                recordStat, MetLevel;
  102.     unsigned long        totalSampleRecord, TotalMilRecord, ActSampleRecord, ActMilRecord;
  103.     SICompletionUPP     mySICompletionUPP;
  104.  
  105.     
  106.     /* use Gestalt to make sure the app will work */
  107.     
  108.     err = Gestalt(gestaltSoundAttr, &feature);
  109.     if (!err) {
  110.         if ((feature & 0x0020) != 0x0020)
  111.             ExitToShell();    // a nice app would inform the user before quiting
  112.         }
  113.     else 
  114.         Debugger();
  115.         
  116.     /* Open sound input drive (whichever one is selected in the sound cdev) */
  117.     
  118.     err = SPBOpenDevice (nil, siWritePermission, &SoundRefNum);
  119.     if (err != noErr)
  120.         Debugger();
  121.         
  122.     myLevel.OnOff = 1;
  123.     myLevel.Level = 150;
  124.     myLevel.Length = 0;
  125.     err = SPBSetDeviceInfo (SoundRefNum,siVoxRecordInfo, (Ptr) &myLevel);
  126.     if (err != noErr)
  127.         Debugger();
  128.         
  129.     myLevel.OnOff = 1;
  130.     myLevel.Level = 50;
  131.     myLevel.Length = 100;
  132.     err = SPBSetDeviceInfo (SoundRefNum,siVoxStopInfo, (Ptr) &myLevel);
  133.     if (err != noErr)
  134.         Debugger();
  135.         
  136.     /* Get the sample rate information for the snd header */
  137.         
  138.     err = SPBGetDeviceInfo (SoundRefNum,siSampleRate, (Ptr) &sampleRate);
  139.     if (err != noErr)
  140.         Debugger();
  141.         
  142.     /* build the four snd buffers */
  143.         
  144.     Buffer = SetUpSounds (Buffer, &headerlength, sampleRate);
  145.     Buffer2 = SetUpSounds (Buffer2, &headerlength2, sampleRate);
  146.     Buffer3 = SetUpSounds (Buffer3, &headerlength3, sampleRate);
  147.     Buffer4 = SetUpSounds (Buffer4, &headerlength4, sampleRate);
  148.     
  149.     /* build the RecordRec pointer and fill in the fields */
  150.         
  151.     RecordRec = (SPBPtr) NewPtr(sizeof (SPB));
  152.     if (MemError() != noErr || RecordRec == nil)
  153.         Debugger();
  154.         
  155.     /* create a Sound input completion UPP */
  156.     mySICompletionUPP = NewSICompletionProc(MyRecComp);
  157.  
  158.     RecordRec->inRefNum = SoundRefNum;
  159.     RecordRec->count =  kbuffSize - headerlength;
  160.     RecordRec->milliseconds = 0;
  161.     RecordRec->bufferLength = kbuffSize - headerlength;
  162.     RecordRec->bufferPtr = (Ptr) ((*Buffer) + headerlength);
  163.     RecordRec->completionRoutine = mySICompletionUPP;
  164.     RecordRec->interruptRoutine = nil;
  165.     RecordRec->userLong = 0;
  166.     RecordRec->error = 0;
  167.     RecordRec->unused1 = 0;
  168.     
  169.     /* open the sound channel which I will need to play from */
  170.  
  171.     chan = nil;
  172.     err = SndNewChannel (&chan, sampledSynth, 0, nil);
  173.     if (err != noErr)
  174.         Debugger();
  175.             
  176.     do {    /* main loop of the app */
  177.         err = SPBRecord (RecordRec, true); // start recording
  178.         if (err != noErr)
  179.             Debugger();
  180.             
  181.         /* The set of if-then-else statements are to determine if the first three buffers
  182.         have been filled with recorded sounds.  If so then which buffer was the last buffer
  183.         to be filled and set the appropriate buffer to be the next buffer to be played. */
  184.         
  185.         if ((RecordRec->userLong & 0x00000008) == 0x00000008) {
  186.             if (RecordRec->bufferPtr == (Ptr) ((*Buffer) + headerlength)) {
  187.                 err = SetupSndHeader (Buffer3, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
  188.                 if (err != noErr)
  189.                     Debugger();
  190.  
  191.                 BufPlay (Buffer3, chan);
  192.                 }
  193.             else  if (RecordRec->bufferPtr == (Ptr) ((*Buffer2) + headerlength2)) {
  194.                 err = SetupSndHeader (Buffer4, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
  195.                 if (err != noErr)
  196.                     Debugger();
  197.  
  198.                 BufPlay (Buffer4, chan);
  199.                 }
  200.             else  if (RecordRec->bufferPtr == (Ptr) ((*Buffer3) + headerlength3)) {
  201.                 err = SetupSndHeader (Buffer, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
  202.                 if (err != noErr)
  203.                     Debugger();
  204.  
  205.                 BufPlay (Buffer, chan);
  206.                 }
  207.             else {
  208.                 err = SetupSndHeader (Buffer2, 1, sampleRate, 8, 'NONE', 0x3C, ActSampleRecord, &dummy);
  209.                 if (err != noErr)
  210.                     Debugger();
  211.  
  212.                 BufPlay (Buffer2, chan);
  213.                 }
  214.             }
  215.             
  216.         do {    /* loop until the recording is done on current buffer */
  217.             } while ((RecordRec->userLong & 0x00000001) == 0);
  218.             
  219.         // Use this for testing the resulting recorded sound, but only when testing
  220.             
  221.         err = SPBGetRecordingStatus(SoundRefNum, &recordStat, &MetLevel, &totalSampleRecord,
  222.                 &ActSampleRecord, &TotalMilRecord, &ActMilRecord);
  223.         if (err != noErr)
  224.             Debugger();
  225.             
  226.         /* Once the Completion rountine has been called I need to set up the next buffer
  227.         to be recorded into.  I do this by going through the if-then-else cases to see 
  228.         which buffer was last filled and set up the next buffer. */
  229.         
  230.         if (RecordRec->bufferPtr == (Ptr) ((*Buffer) + headerlength))
  231.             RecordRec->bufferPtr = (Ptr) ((*Buffer2) + headerlength2);
  232.             
  233.         else  if (RecordRec->bufferPtr == (Ptr) ((*Buffer2) + headerlength2))
  234.             RecordRec->bufferPtr = (Ptr) ((*Buffer3) + headerlength3);
  235.             
  236.         else  if (RecordRec->bufferPtr == (Ptr) ((*Buffer3) + headerlength3))
  237.             RecordRec->bufferPtr = (Ptr) ((*Buffer4) + headerlength4);
  238.             
  239.         else
  240.             RecordRec->bufferPtr = (Ptr) ((*Buffer) + headerlength);    
  241.         
  242.         /* I need to reset the recording current buffer field*/
  243.         
  244.         RecordRec->userLong &= 0xFFFFFFFE;
  245.         
  246.         /* When the mouse button is found down, it is time to quit */
  247.         
  248.         } while (!Button());
  249.         
  250.     /* Once I am out of the loop it is time to clean up - stop the currently playing sound,
  251.     Dispose of the Channel, close the input driver, and dispose of the buffer handles and
  252.     RecordRec Ptr. */
  253.         
  254.     mycmd.cmd = quietCmd;
  255.     mycmd.param1 = 0;
  256.     mycmd.param2 = 0;
  257.     
  258.     err = SndDoImmediate (chan, &mycmd);
  259.     if (err != noErr)
  260.         Debugger();
  261.  
  262.     err = SndDisposeChannel (chan,false);
  263.     if (err != noErr)
  264.         Debugger();
  265.  
  266.     SPBCloseDevice (SoundRefNum);
  267.         
  268.     HUnlock (Buffer);
  269.     HUnlock (Buffer2);
  270.     HUnlock (Buffer3);
  271.     HUnlock (Buffer4);
  272.     DisposeHandle (Buffer);
  273.     DisposeHandle (Buffer2);
  274.     DisposeHandle (Buffer3);
  275.     DisposeHandle (Buffer4);
  276.     DisposePtr ((Ptr) RecordRec);
  277.     
  278.     DisposeRoutineDescriptor(mySICompletionUPP);
  279. }
  280. /**********************************/
  281.  
  282. pascal void MyRecComp (SPBPtr inParamPtr)
  283.  
  284. /* This is the Completion Routine which is called every time the buffer, which is being 
  285. recorded into, is full.  */
  286.  
  287. {
  288.     long    local;
  289.     
  290.     local = inParamPtr->userLong;
  291.     
  292.     local &= 0x00000038;
  293.     
  294.     /* I need to check for the first three times this routine is called so I know when it
  295.     is safe to start playing buffers. */
  296.     
  297.     if (local != 0x00000008) { 
  298.         if (local == 0x00000000)
  299.             local = 0x00000010;
  300.         else if (local == 0x00000010)
  301.             local = 0x00000020;
  302.         else
  303.             local = 0x00000008;
  304.         }
  305.         
  306.     inParamPtr->userLong &= 0xFFFFFFC5;    
  307.     inParamPtr->userLong |= local;    
  308.     
  309.     /* inform the app that the recording is done */
  310.         
  311.     inParamPtr->userLong |= 0x00000001;    
  312.  
  313.     return;
  314. }
  315.  
  316. /**********************************/
  317. /* Bit definitions .....
  318. 31
  319. 30
  320. 29
  321. 28
  322. 27
  323. 26
  324. 25
  325. 24
  326. 23
  327. 22
  328. 21
  329. 20
  330. 19
  331. 18
  332. 17
  333. 16
  334. 15
  335. 14
  336. 13
  337. 12
  338. 11
  339. 10
  340. 09
  341. 08
  342. 07
  343. 06
  344. 05 - finished recording to the second buffer
  345. 04 - finished recording to the first buffer
  346. 03 - finished recording to the first three buffers
  347. 02
  348. 01
  349. 00 - finished recording to current buffer
  350. */